package logger.sd.server.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import logger.sd.server.LoggingServer;
import logger.sd.server.MonothreadLoggingServer;
import logger.sd.server.ServerConfiguration;

/**
 * Classe para testar o Token Ring
 * 
 * @author wendell
 *
 */
public class TokenRingTest implements Observer {
	
	protected List<LoggingServer> serverList;
	protected List<ServerConfiguration> configList;
	protected Map<Integer, Integer> ports;
	
	private Integer origem;
	private Integer destino;
	private int count;

	/**
	 * Construtor
	 */
	public TokenRingTest() {
		initializeTest();
		for(LoggingServer server:serverList) {
			server.addListener(this);
		}
		origem = new Integer(7070);
		count = 0;
	}
	
	/**
	 * Inicializador
	 */
	private void initializeTest() {

		configList = new ArrayList<ServerConfiguration>();
		configList.add(new ServerConfiguration("config01"));
		configList.add(new ServerConfiguration("config02"));
		configList.add(new ServerConfiguration("config03"));

		String[][] argsTemp = {
				{ "7070", "localhost:7071", "log00.log",
						"localhost:7071,localhost:7072", "-first" },
				{ "7071", "localhost:7072", "log01.log",
						"localhost:7070,localhost:7072" },
				{ "7072", "localhost:7070", "log02.log",
						"localhost:7070,localhost:7071" } };

		ports = new HashMap<Integer, Integer>();
		// ports = (from, to)
		ports.put(7070, 7071);
		ports.put(7071, 7072);
		ports.put(7072, 7070);

		serverList = new ArrayList<LoggingServer>();

		for (int i = 0; i < configList.size(); ++i) {
			parse(configList.get(i), argsTemp[i]);
			serverList.add(new MonothreadLoggingServer(configList.get(i)));
			serverList.get(i).setConfig(configList.get(i));

		}
	}

	/**
	 * Funcao que le os argumentos da linha de comando.
	 * 
	 * @param args
	 */
	private void parse(ServerConfiguration config, String[] args) {

		config.setFirst(false);
		List<String> servers = new ArrayList<String>();

		config.setPort(args[0]);
		String[] address = args[1].split(":");
		config.setNextHost(address[0]);
		config.setNextPort(address[1]);
		config.setLogfile(args[2]);
		String[] others = args[3].split(",");
		for (int i = 0; i < others.length; ++i) {
			servers.add(others[i]);
		}
		config.setOthersServers(servers);

		if (args.length > 4) {
			config.setFirst(args[4].equals("-first"));
		}
	}

	/**
	 * Inici aos servidores
	 */
	public void runServers() {

		Thread t01 = new Thread(new Runnable() {

			@Override
			public void run() {
				serverList.get(0).start();
			}
		});
		t01.start();

		Thread t02 = new Thread(new Runnable() {

			@Override
			public void run() {
				serverList.get(1).start();
			}
		});
		t02.start();

		Thread t03 = new Thread(new Runnable() {

			@Override
			public void run() {
				serverList.get(2).start();
			}
		});
		t03.start();
	}

	
	/**
	 * Testa a passagem de token
	 */
	public void testTokenRing() {
		System.out.println("========= Teste do Token Ring =======");
		System.out.println("O token comeca em localhost:7070");
		
		this.runServers();
	}
	
	/**
	 * Implementa o Observer
	 */
	@Override
	public void update(Observable arg0, Object arg1) {

		destino = ((LoggingServer) arg0).getConfig().getPort();
		System.out.println("O token chegou em localhost:" + destino);

		System.out.println("Origem do token: " + origem);
		System.out.println("Destino do token: " + destino);

		if (ports.get(origem).equals(destino)) {
			System.out.println("Token recebido corretamente\n ---------- ");
			origem = destino;
		} else {
			System.err.println("Token recebido fora de ordem\n ---------- ");
		}

		count++;
		if (count >= 6) {
			System.out.println("Fim do teste de Token Ring");
			System.exit(0);
		}
	}
	
	/**
	 * Main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		TokenRingTest test = new TokenRingTest();
		test.testTokenRing();
	}
}
